func coinChange(coins []int, amount int) int {
    /*
        1. 定义
            dp[i] 表示 组合的总金额为 amount  最少有 dp[i] 个硬币
        2. 递归
            dp[i] =min(dp[i], dp[i-coins[i]]+1) 
        3. 遍历顺序
            组合，所以先遍历物品，再遍历背包
        4. 初始化
            dp[0] = 0
        5. 推导dp数组
            0 1 2 3
        1   0 1 2 3
        2   0 1 1 2 
        5   0 1 2 2

            0 1 2 3
        2   0 M 1 M
    */
    dp := make([]int, amount+1)
    for i:=1; i<len(dp); i++{
        dp[i] = math.MaxInt
    }

    for i:=0; i<len(coins); i++{ // 先遍历物品
        for j:=coins[i]; j<=amount; j++ {   // 再遍历背包
            if dp[j-coins[i]] != math.MaxInt {
                dp[j] = min(dp[j], dp[j-coins[i]]+1)
            }
        }
    }
    if dp[amount] == math.MaxInt {
        return -1
    }
    return dp[amount]
}

func min(a , b int) int {
    if a>b {
        return b
    }
    return a
}